package com.vf.cloud.api.biz.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.vf.cloud.api.biz.service.IRender;
import com.vf.cloud.common.constant.Cache;
import com.vf.cloud.common.domain.Client;
import com.vf.cloud.common.domain.Config;
import com.vf.cloud.common.domain.Project;
import com.vf.cloud.common.util.R;
import com.vf.cloud.common.util.UuidUtil;
import com.vf.cloud.common.vo.OrderParamVo;
import com.vf.cloud.common.vo.OrderVo;
import com.vf.cloud.server.adapter.AdapterServer;
import com.vf.cloud.server.signalling.SignallingServer;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class RenderImpl implements IRender {

//	public static void main(String[] args) {
//
//		String nodeUrl = String.format("http://%s:%s/Renderers/Any/order", "127.0.0.1", "8880");
//		HttpClient httpClient = new HttpClient();
//		PostMethod method = new PostMethod(nodeUrl);
//		try {
//
//			method.addRequestHeader("Content-Type", "application/json");
//
//			OrderParamVo param = new OrderParamVo();
//			param.setOrder("111");
//			param.setHeight(100);
//			param.setWidth(100);
//
//			RequestEntity requestEntity = new StringRequestEntity(JsonKit.toJson(param), "application/json", "UTF-8");
//
//			method.setRequestEntity(requestEntity);
//			int code = httpClient.executeMethod(method);
//			if (code == 200) {
//				String result = new String(method.getResponseBody(), "UTF-8");
//				System.out.println("result=" + result);
//			}
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//	}

	@Override
	public R<OrderVo> ColonyOrder(OrderParamVo param) {

		if (param == null) {
			return R.failed("参数必填.");
		}

		if (StrKit.isBlank(param.getOrder())) {
			return R.failed("参数必填.");
		}

		Client client = Client.dao.findFirst("select * from " + Client.TABLE_NAME + " where surplus>0 ");
		if (client == null) {
			return R.failed("资源已达上限，请先释放资源.");
		}

		Config config = Config.dao.findById("VFCloud_2022");
		if (config != null && StrKit.equals(config.getLocalPwd(), client.getPassword())) {
			return AnyOrder(param);
		}

		String nodeUrl = String.format("http://%s:%s/Renderers/Any/order", client.getIp(), client.getPort());
		HttpClient httpClient = new HttpClient();

		PostMethod method = new PostMethod(nodeUrl);
		try {
			RequestEntity requestEntity = new StringRequestEntity(JsonKit.toJson(param), "application/json", "UTF-8");
			method.setRequestEntity(requestEntity);
			int code = httpClient.executeMethod(method);
			if (code == 200) {
				JSONObject result = JSONObject.parseObject(new String(method.getResponseBody(), "UTF-8"));
				if (result.containsKey("code") && result.getInteger("code") == 200) {
					return R.ok(JSONObject.parseObject(result.getString("data"), OrderVo.class));
				} else if (result.containsKey("code") && result.getInteger("code") == 500) {
					return R.failed(result.getString("message"));
				} else {
					return R.failed(result.getString("message"));
				}
			} else {
				return R.failed(String.format("网络异常:【%s】.", code));
			}
		} catch (IOException e) {
			return R.failed(e.getMessage());
		}
	}

	@Override
	public R<OrderVo> AnyOrder(OrderParamVo param) {
		if (param == null) {
			return R.failed("参数必填.");
		}

		if (StrKit.isBlank(param.getOrder())) {
			return R.failed("参数必填.");
		}

		Project project = Project.dao.findById(param.getOrder());
		if (project == null) {
			return R.failed("无效order.");
		}

		if (Cache.signalling == null) {
			return R.failed("信令服务器不存在.");
		}

		int status = SignallingServer.getInstance().getStatus();
		if (2 != status) {
			if (-1 == status) {
				return R.failed("信令服务不可用，无法提供渲染服务.");
			} else if (1 == status) {
				return R.failed("信令服务正在启动中，无法提供渲染服务.");
			} else if (0 == status) {
				return R.failed("信令服务已停止，无法提供渲染服务.");
			} else if (3 == status) {
				return R.failed("信令服务停止中，无法提供渲染服务.");
			}
		}

		String key = UuidUtil.genKey();
		R<Integer> gpu = AdapterServer.getInstance().applyGPU(key);

		if (gpu.getCode() != 200) {
			return R.failed(gpu.getMessage());
		}

		Runtime runtime = Runtime.getRuntime();
		String cmd = String.format(
				"cmd /c start /b %s -ForceRes -RenderOFFscreen -AudioMixer -AllowPixelStreamingCommands "
						+ "ResX=%s ResY=%s," + "-PixelStreamingURL=%s " + "-GraphicsAdapter=%s " + "-AppId=%s "
						+ "-key=%s " + "-NvEncFrameRateNum=%s -PixelStreamingHideCursor=true %s",
				project.getExeFilePath(), param.getWidth(), param.getHeight(),
				String.format("ws://%s:%s/%s", Cache.signalling.getSignalingInnerIP(),
						Cache.signalling.getSignalingInnerPort(), key),
				gpu.getResult(), project.getId(), key, Integer.parseInt(project.getFrameRate()),
				project.getStartupParameter());
		OrderVo order = new OrderVo();
		order.setUrl(String.format("ws://%s:%s?EIO=%s", Cache.signalling.getSignalingIP(),
				Cache.signalling.getSignalingPort(), key));
		order.setAppId(project.getId());
		order.setProjectId(project.getId());
		order.setRenderingEngine(project.getRenderingEngine());
		order.setExpiresIn(System.currentTimeMillis());

		Process process;
		try {
			process = runtime.exec(cmd);
			new Thread(new ConsoleThread(new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"))))
					.start();
			if (process.waitFor() == 0) {
				return R.ok(order);
			}
		} catch (IOException | InterruptedException e) {
			e.printStackTrace();
		}

		return R.failed();
	}

	class ConsoleThread implements Runnable {
		private BufferedReader bfr = null;

		public ConsoleThread(BufferedReader bfr) {
			this.bfr = bfr;
		}

		@Override
		public void run() {
			String line = null;
			try {
				while ((line = bfr.readLine()) != null) {
					log.debug(line);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
